﻿namespace EFS.AD
{
	/// Class Domain
	public class Domain : System.Collections.IEnumerable
	{
		// users by logon
		private System.Collections.Generic.Dictionary<System.String, EFS.AD.User> hashLogonUsers = new System.Collections.Generic.Dictionary<System.String, EFS.AD.User>(System.StringComparer.OrdinalIgnoreCase);

		// users by SIP 
		private System.Collections.Generic.Dictionary<System.String, EFS.AD.User> hashSipUsers = new System.Collections.Generic.Dictionary<System.String, EFS.AD.User>(System.StringComparer.OrdinalIgnoreCase);

		// users by TEL
		private System.Collections.Generic.Dictionary<System.String, EFS.AD.User> hashTelUsers = new System.Collections.Generic.Dictionary<System.String, EFS.AD.User>(System.StringComparer.OrdinalIgnoreCase);

		// users by EXT
		private System.Collections.Generic.Dictionary<System.String, EFS.AD.User> hashExtUsers = new System.Collections.Generic.Dictionary<System.String, EFS.AD.User>(System.StringComparer.OrdinalIgnoreCase);

		// users by guid
		private System.Collections.Generic.Dictionary<System.Guid, EFS.AD.User> hashGuidUsers = new System.Collections.Generic.Dictionary<System.Guid, EFS.AD.User>();

		/// Contructor
		public Domain()
		{
			// init
			InitUsers();
		}

		#region Properties

		/// Property Name: Get, Set
		public System.String Name { get; private set; }

		/// <summary>
		/// GetBySIP
		/// </summary>
		/// <param name="sip"></param>
		/// <returns></returns>
		public EFS.AD.User GetBySIP(System.String sip)
		{
			// get 
			if (hashSipUsers.ContainsKey(sip))
			{
				return hashSipUsers[sip];
			}

			// not found
			return null;
		}

		/// <summary>
		/// GetByTEL
		/// </summary>
		/// <param name="sip"></param>
		/// <returns></returns>
		public EFS.AD.User GetByTEL(System.String tel)
		{
			// get 
			if (hashTelUsers.ContainsKey(tel))
			{
				return hashTelUsers[tel];
			}

			// not found
			return null;
		}

		/// <summary>
		/// GetByEXT
		/// </summary>
		/// <param name="sip"></param>
		/// <returns></returns>
		public EFS.AD.User GetByEXT(System.String ext)
		{
			// get 
			if (hashExtUsers.ContainsKey(ext))
			{
				return hashExtUsers[ext];
			}

			// not found
			return null;
		}

		/// <summary>
		/// GetByLogonName
		/// </summary>
		/// <param name="logonName"></param>
		/// <returns></returns>
		public EFS.AD.User GetByLogonName(System.String logonName)
		{
			// get 
			if (hashLogonUsers.ContainsKey(logonName))
			{
				return hashLogonUsers[logonName];
			}

			// not found
			return null;
		}

		/// <summary>
		/// GetByGuid
		/// </summary>
		/// <param name="guid"></param>
		/// <returns></returns>
		public EFS.AD.User GetByGuid(System.Guid guid)
		{
			// get 
			if (hashGuidUsers.ContainsKey(guid))
			{
				return hashGuidUsers[guid];
			}

			// not found
			return null;
		}

		/// Filter
		public EFS.AD.User[] Filter(
			System.String partialLogonName,
			System.Boolean? hasSIP,
			System.String partialName,
			System.Boolean caseSensitive)
		{
			// create list
			System.Collections.Generic.List<EFS.AD.User> retValue = new System.Collections.Generic.List<EFS.AD.User>();

			// cicle all
			foreach (System.Collections.Generic.KeyValuePair<System.Guid, EFS.AD.User> keyPairUser in hashGuidUsers)
			{
				if (keyPairUser.Value.Match(partialLogonName, hasSIP, partialName, caseSensitive))
				{
					retValue.Add(keyPairUser.Value);
				}
			}

			// ok
			return retValue.ToArray();
		}

		#endregion

		#region InitData

		/// InitUsers
		private void InitUsers()
		{
			// cicle all
			foreach (EFS.AD.User user in LoadAllUsers())
			{
				// user logon map
				if (EFS.Common.Verify.String(user.LogonName) && EFS.Common.Verify.String(user.FirstName) && EFS.Common.Verify.String(user.LastName))
				{
					// user guid map
					hashGuidUsers[user.ObjectGuid] = user;

					// add logon map
					hashLogonUsers[user.LogonName] = user;

                    // sip
                    if (EFS.Common.Verify.String(user.SIP))
                    {
    					// user sip map
	    				hashSipUsers[user.SIP] = user;
                    }

					// user tel map
					if (EFS.Common.Verify.String(user.TEL))
					{
						hashTelUsers[user.TEL] = user;
					}

					// user ext map
					if (EFS.Common.Verify.String(user.EXT))
					{
						hashExtUsers[user.EXT] = user;
					}
				}
			}
		}

		/// <summary>
		/// Load all users
		/// </summary>
		/// <returns></returns>
		private EFS.AD.User[] LoadAllUsers()
		{
			EFS.AD.User[] users = null;

			try
			{
				//get the directory entry for the LDAP root folder
				using (System.DirectoryServices.DirectoryEntry entry = Current.RootDirectoryEntry)
				{
					//set the root LDAP folder into the directory searcher object
					using (System.DirectoryServices.DirectorySearcher directorySearcher = new System.DirectoryServices.DirectorySearcher(entry))
					{
						//set the filter name to the logon name
						directorySearcher.Filter = ("(objectCategory=person)");

						// search
						using (System.DirectoryServices.SearchResultCollection searchResultCollection = directorySearcher.FindAll())
						{
							// log
							// ~ commented for performance ~ EFS.EventLog.Log.LogInfo(System.String.Format("Directory Search results count: {0} ", searchResultCollection.Count), new System.Diagnostics.StackTrace());

							// local collection
							System.Collections.Generic.List<EFS.AD.User> localList = new System.Collections.Generic.List<User>();

							// load all the list
							foreach (System.DirectoryServices.SearchResult adSearchResult in searchResultCollection)
							{
								// use search
								using (System.DirectoryServices.DirectoryEntry directoryEntry = adSearchResult.GetDirectoryEntry())
								{
									localList.Add(Misc.Functions.UserFrom(directoryEntry));
								}
							}

							// make array
							users = localList.ToArray();
						}
					}
				}
			}
			catch (System.Exception ex)
			{
				EFS.EventLog.Log.LogException(ex, null);
			}

			// done
			return users;
		}

		#endregion

		#region Utilities

		/// IsUserMemberOf
		public System.Boolean IsUserMemberOf(System.String userLogonName, System.String groupName)
		{
			// get context
			System.DirectoryServices.AccountManagement.PrincipalContext principalContext =
				new System.DirectoryServices.AccountManagement.PrincipalContext(System.DirectoryServices.AccountManagement.ContextType.Domain);

			// get user
			System.DirectoryServices.AccountManagement.UserPrincipal user =
				System.DirectoryServices.AccountManagement.UserPrincipal.FindByIdentity(
					principalContext,
					System.DirectoryServices.AccountManagement.IdentityType.SamAccountName,
					userLogonName);

			// test user
			if (null == user)
			{
				return false;
			}

			// get user
			System.DirectoryServices.AccountManagement.GroupPrincipal group =
				System.DirectoryServices.AccountManagement.GroupPrincipal.FindByIdentity(principalContext, groupName);

			// test group
			if (null == group)
			{
				return false;
			}

			// ok
			return user.IsMemberOf(group);
		}

		/// <summary>
		/// Get numerator
		/// </summary>
		/// <returns></returns>
		public System.Collections.IEnumerator GetEnumerator()
		{
			return hashGuidUsers.Values.GetEnumerator();
		}

		#endregion
	}

}